package com.wanyang.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.wanyang.aliyun.AfterScan;
import com.wanyang.aliyun.dto.ImageTaskDTO;
import com.wanyang.aliyun.dto.TextTaskDTO;
import com.wanyang.aliyun.dto.VideoTaskDTO;
import com.wanyang.aliyun.service.AliyunContentScanService;
import com.wanyang.bo.MemberBO;
import com.wanyang.constant.BusinessTypeConstant;
import com.wanyang.dao.CategoryDao;
import com.wanyang.dao.CommonDao;
import com.wanyang.dao.PostDao;
import com.wanyang.dao.SearchDao;
import com.wanyang.dos.*;
import com.wanyang.dto.AuditObject;
import com.wanyang.dto.PageDTO;
import com.wanyang.dto.PostPublishBase;
import com.wanyang.dto.SearchDTO;
import com.wanyang.exception.ApiException;
import com.wanyang.mapper.*;
import com.wanyang.utils.DateUtil;
import com.wanyang.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PostServiceImpl implements PostService {

    @Resource
    private PostDao postDao;

    @Resource
    private PostDOMapper postDOMapper;

    @Resource
    private CategoryDao categoryDao;

    @Autowired
    private MemberService memberService;

    @Autowired
    private PostCommentService postCommentService;

    @Autowired
    private MemberLikeService memberLikeService;

    @Resource
    private MemberBrowseDOMapper memberBrowseDOMapper;

    @Autowired
    private MemberBrowseService memberBrowseService;

    @Resource
    private MemberCollectDOMapper memberCollectDOMapper;

    @Resource
    private SearchDao searchDao;

    @Autowired
    private SearchService searchService;

    @Autowired
    private AliyunContentScanService aliyunContentScanService;

    @Resource
    private CommonDao commonDao;

    @Resource
    private IllegalContentDOMapper illegalContentDOMapper;

    @Resource
    private AsyncScanRecordDOMapper asyncScanRecordDOMapper;

    @Resource
    private GoldRecordDOMapper goldRecordDOMapper;

    @Autowired
    private FollowerService followerService;

    @Override
    @Transactional
    public void publish(PostPublishBase postPublishBase) {
        Integer memberId = UserContext.get().getId();
        // areaId 写死
        postPublishBase.setAreaId(Constants.defaultAreaId);
        postPublishBase.setPublisherId(UserContext.get().getId());

        if (log.isDebugEnabled())
            log.debug("postPublishBase : {}", JSONUtil.toJsonStr(postPublishBase));

        postPublishBase.convertDetailAndCover();

        Integer postId;

        if (postPublishBase.getId() != null) {
            postId = postPublishBase.getId();
            // update
            PostDO postDO = new PostDO();
            postDO.setId(postPublishBase.getId());
            postDO.setTitle(postPublishBase.getTitle());
            postDO.setDetail(postPublishBase.getDetail());
            postDO.setIsPublish(postPublishBase.getIsPublish());
            postDO.setLastedUpdateTime(DateUtil.currentUnixTime());
            postDO.setIsApproved(true);
            postDOMapper.updateByPrimaryKeySelective(postDO);

        } else {
            // insert
            PostDO postDO = new PostDO();
            Integer currentUnixTime = DateUtil.currentUnixTime();
            postDO.setCreateTime(currentUnixTime);
            postDO.setLastedUpdateTime(currentUnixTime);
            postDO.setIsApproved(true);
            postDO.setIsTop(false);
            postDO.setIsDelete(false);
            postDO.setCommentsNumber(0);
            postDO.setLikesNumber(0);

            BeanUtils.copyProperties(postPublishBase, postDO);

            postDO.setIsPublish(postPublishBase.getIsPublish());
            postDOMapper.insertSelective(postDO);
            postId = commonDao.mysqlLastId();
        }



        AuditObject needAuditObject = postPublishBase.getNeedAuditObject();

        List<String> contents = needAuditObject.getContents();

        // 文本审核
        if (CollectionUtil.isNotEmpty(contents)) {
            StringBuilder sb = new StringBuilder();
            contents.forEach(str -> sb.append(str).append(" "));
            String needAuditContent = sb.toString();

            TextTaskDTO textTaskDTO = new TextTaskDTO(UUID.randomUUID().toString(), needAuditContent);

            aliyunContentScanService.syncTextScan(Collections.singletonList(textTaskDTO), initAfterScan(postId, JSONUtil.toJsonStr(textTaskDTO)));
        }

        // 视频审核
        List<String> videoList = needAuditObject.getVideoList();

        if (CollectionUtil.isNotEmpty(videoList)) {
            List<VideoTaskDTO> videoTaskDTOs = new ArrayList<>();
            for (String url : videoList) {
                VideoTaskDTO videoTaskDTO = new VideoTaskDTO();
                videoTaskDTO.setDataId(UUID.randomUUID().toString());
                videoTaskDTO.setUrl(url);
                videoTaskDTOs.add(videoTaskDTO);
            }

            JSONArray jsonArray = aliyunContentScanService.videoAsyncScan(videoTaskDTOs);

            List<AsyncScanRecordDO> scanRecordDOList = new ArrayList<>();

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject json = jsonArray.getJSONObject(i);
                AsyncScanRecordDO asyncScanRecordDO = new AsyncScanRecordDO();
                asyncScanRecordDO.setTaskId(json.getString("taskId"));
                asyncScanRecordDO.setBusinessId(postId);
                asyncScanRecordDO.setBusinessType(BusinessTypeConstant.POST);
                asyncScanRecordDO.setCreateTime(DateUtil.currentUnixTime());
                scanRecordDOList.add(asyncScanRecordDO);
            }

            for (AsyncScanRecordDO asyncScanRecordDO : scanRecordDOList) {
                asyncScanRecordDOMapper.insertSelective(asyncScanRecordDO);
            }

        }

        // 图片审核
        List<String> imgList = needAuditObject.getImgList();

        if (CollectionUtil.isNotEmpty(imgList)) {
            List<ImageTaskDTO> imageTaskDTOs = new ArrayList<>();

            for (String url : imgList) {
                ImageTaskDTO imageTaskDTO = new ImageTaskDTO();
                imageTaskDTO.setDataId(UUID.randomUUID().toString());
                imageTaskDTO.setTime(new Date());
                imageTaskDTO.setUrl(url);
                imageTaskDTOs.add(imageTaskDTO);
            }

            aliyunContentScanService.imageSyncScan(imageTaskDTOs, initAfterScan(postId, JSONUtil.toJsonStr(imageTaskDTOs)));

        }


        // TODO 积分奖励规则需要查询

        // 查询该帖子是否已经给过奖励了
        GoldRecordDOExample example = new GoldRecordDOExample();
        example.createCriteria().andMemberIdEqualTo(memberId)
                .andBusinessIdEqualTo(postId)
                .andBusinessTypeEqualTo(BusinessTypeConstant.POST);

        long l = goldRecordDOMapper.countByExample(example);

        if (l == 0) {
            GoldRecordDO goldRecordDO = new GoldRecordDO();
            goldRecordDO.setGold(new BigDecimal(10));
            goldRecordDO.setCreateTime(DateUtil.currentUnixTime());
            goldRecordDO.setBusinessId(postId);
            goldRecordDO.setBusinessType(BusinessTypeConstant.POST);
            goldRecordDO.setRemark("帖子发布");
            goldRecordDO.setMemberId(memberId);
            goldRecordDOMapper.insertSelective(goldRecordDO);
        }


        postPublishBase.afterPublish();
    }

    private AfterScan initAfterScan(Integer postId, String s) {
        return (dataId, pass) -> {
            if (!pass) {
                PostDO update = new PostDO();
                update.setId(postId);
                update.setIsApproved(false);
                postDOMapper.updateByPrimaryKeySelective(update);

                // 记录违规数据
                IllegalContentDO illegalContentDO = new IllegalContentDO();
                illegalContentDO.setBusinessId(postId);
                illegalContentDO.setBusinessType(BusinessTypeConstant.POST);
                illegalContentDO.setMemeberId(UserContext.get().getId());
                illegalContentDO.setCreateTime(DateUtil.currentUnixTime());
                illegalContentDO.setAliyunResponse(null);
                illegalContentDO.setContent(s);
                illegalContentDOMapper.insertSelective(illegalContentDO);
            }
        };
    }

    @Resource
    private JobDOMapper jobDOMapper;

    @Override
    public List<JobDO> queryJobList() {
        JobDOExample example = new JobDOExample();
        example.createCriteria().andIsDeleteEqualTo(false);
        return jobDOMapper.selectByExample(example);
    }

    @Override
    public List<CategoryDO> queryAreaCategories(Integer areaId) {
        return categoryDao.queryAreaCategories(areaId);
    }

    @Override
    public List<TopPostVO> queryTopPost(Integer postCategoryId, Integer areaId) {
        return postDao.queryTopPost(postCategoryId, areaId);
    }

    @Override
    public List<PostVO> queryVOList(Integer postCategoryId, Integer areaId, PageDTO pageDTO) {
        PageHelper.startPage(pageDTO);
        return handlePostVO(postDao.queryVOList(postCategoryId, areaId));
    }

    @Override
    public PostDetailVO queryDetail(Integer postId) {
        PostDetailVO detailVO = new PostDetailVO();

        PostDO post = postDOMapper.selectByPrimaryKey(postId);

        BeanUtil.copyProperties(post, detailVO);

        if (!post.getIsApproved() || post.getIsDelete() || !post.getIsPublish()) {
            throw new ApiException("帖子找不到了");
        }

        PublisherVO publisherVO = memberService.getPublisherVO(post.getPublisherId());
        List<PostCommentVO> postCommentVOS = postCommentService.queryDefaultComment(postId);

        detailVO.setPostCommentVOS(postCommentVOS);
        detailVO.setPublisherVO(publisherVO);

        MemberBO memberBO = UserContext.get();

        detailVO.setDetailObject(JSONUtil.parse(detailVO.getDetail()));

        if (memberBO != null) {
            List<Integer> likeIds = memberLikeService.queryLikes(memberBO.getId(), MemberLikeService.like_type_post,
                    Collections.singletonList(postId));

            if (likeIds.contains(postId)) {
                // 用户是否点赞
                detailVO.setLike(true);
            }

            // 加入最近浏览，可以异步
            boolean update = memberBrowseService.updateTimeIfExist(memberBO.getId(), postId);

            if (!update) {
                MemberBrowseDO memberBrowseDO = new MemberBrowseDO();
                memberBrowseDO.setMemberId(memberBO.getId());
                memberBrowseDO.setPostId(postId);
                memberBrowseDO.setCreateTime(DateUtil.currentUnixTime());
                memberBrowseDOMapper.insertSelective(memberBrowseDO);
            }

            memberBrowseService.delEarliestRecordIfNecessary(memberBO.getId());

        }

        return detailVO;
    }

    @Override
    public List<PostVO> queryLastBrowse(Integer memberId, PageDTO pageDTO) {
        PageHelper.startPage(pageDTO);
        return handlePostVO(postDao.queryLastBrowse(memberId));
    }

    @Override
    public void delBrowse(List<Integer> postIds) {
        MemberBrowseDOExample example = new MemberBrowseDOExample();
        example.createCriteria()
                .andMemberIdEqualTo(UserContext.get().getId())
                .andPostIdIn(postIds);

        memberBrowseDOMapper.deleteByExample(example);
    }

    @Override
    public void collectOrCancel(Integer postId) {
        Integer memberId = UserContext.get().getId();

        MemberCollectDOExample example = new MemberCollectDOExample();
        example.createCriteria()
                .andMemberIdEqualTo(memberId)
                .andPostIdEqualTo(postId);
        long count = memberCollectDOMapper.countByExample(example);

        if (count == 1) {
            memberCollectDOMapper.deleteByPrimaryKey(memberId, postId);
        } else {
            MemberCollectDO collectDO = new MemberCollectDO();
            collectDO.setMemberId(memberId);
            collectDO.setPostId(postId);
            collectDO.setCreateTime(DateUtil.currentUnixTime());
            memberCollectDOMapper.insert(collectDO);

        }

    }

    @Override
    public List<PostVO> queryCollect(Integer memberId, PageDTO pageDTO) {
        PageHelper.startPage(pageDTO);
        return handlePostVO(postDao.queryCollect(memberId));
    }


    private List<PostVO> handlePostVO(List<PostVO> postVOList) {
        MemberBO currentMember = UserContext.get();
        List<Integer> currentLikes = new ArrayList<>();

        if (currentMember != null && CollectionUtil.isNotEmpty(postVOList)) {
            List<Integer> postIds = postVOList.stream().map(PostVO::getId).collect(Collectors.toList());
            currentLikes = memberLikeService.queryLikes(currentMember.getId(), MemberLikeService.like_type_post, postIds);
        }

        for (PostVO postVO : postVOList) {
            postVO.setDetailObject(JSONUtil.parse(postVO.getDetail()));

            if (StringUtils.isNotEmpty(postVO.getCovers())){
                List<String> coverList = JSONUtil.toList(JSONUtil.parseArray(postVO.getCovers()), String.class);
                postVO.setCoverList(coverList);
            }

            postVO.setCreateTimeStr(DateUtil.handleTime(postVO.getCreateTime()));

            if (CollectionUtil.isNotEmpty(currentLikes)) {
                if (currentLikes.contains(postVO.getId())) {
                    postVO.setLike(true);
                }
            }

        }

        return postVOList;
    }

    @Override
    public List<PostDO> queryDraft(Integer memberId, PageDTO pageDTO) {
        PageHelper.startPage(pageDTO);

        PostDOExample example = new PostDOExample();
        example.createCriteria()
                .andPublisherIdEqualTo(memberId)
                .andIsPublishEqualTo(false)
                .andIsDeleteEqualTo(false);
        return postDOMapper.selectByExample(example);
    }

    @Override
    public List<PostVO> queryMemberPosts(Integer memberId, PageDTO pageDTO) {
        PageHelper.startPage(pageDTO);
        return handlePostVO(postDao.queryMemberPosts(memberId));
    }

    @Override
    public List<?> search(SearchDTO searchDTO) {
        List<?> result;
        PageHelper.startPage(searchDTO);

        if (SearchDTO.Type.POST.equals(searchDTO.getType())) {
            List<PostVO> postVOS = searchDao.searchByPost(searchDTO.getSearchContent());
            result = handlePostVO(postVOS);
        } else if (SearchDTO.Type.MEMBER.equals(searchDTO.getType())) {
            result = followerService.search(searchDTO.getSearchContent());
        } else {
            result = new ArrayList<>();
        }

        searchService.writeSearchHistory(searchDTO);
        return result;
    }

}
